package com.itheima.health.interceptor;

import com.itheima.health.common.SessionConst;
import com.itheima.health.exception.BusinessRuntimeException;
import com.itheima.health.pojo.entity.Permission;
import com.itheima.health.pojo.entity.Role;
import com.itheima.health.properties.AuthorityProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

@Slf4j
public class AuthorityInterceptor implements HandlerInterceptor {

    private final AuthorityProperties authorityProperties;

    public AuthorityInterceptor(AuthorityProperties authorityProperties) {
        this.authorityProperties = authorityProperties;
    }

    //TODO 登录和注册成功后，设置session时都要设置role权限
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String method = request.getMethod();
        String path = request.getRequestURI();
        String[] pathItem = path.split("/");
        log.info("拦截请求--{}，请求方式--{}", path, method);
        HttpSession session = request.getSession();
        Set<Role> roleSet = (Set<Role>) session.getAttribute(SessionConst.SESSION_ROLE);

        //遍历配置文件，判断是否需要拦截
        List<AuthorityProperties.Authority> authorities = authorityProperties.getAuthorities();
        if (authorities==null) return true;
        for (AuthorityProperties.Authority authority : authorities) {
            //死只能匹配三层的死逻辑
            //匹配请求路径和请求类型,匹配成功则说明该请求需要对应的权限
//            if (path.equals(authority.getPath()) && method.equals(authority.getMethod())) {
//                //判断当前用户权限是否存在请求资源需要的权限
////                if (roleSet != null && !roleSet.isEmpty()) {
////                    //遍历角色
////                    for (Role role : roleSet) {
////                        //判断当前角色自身是否包含请求资源需要的权限
////                        if (role.getKeyword().equals(authority.getKeyword())) {
////                            log.info("角色自身请求权限足够，放行");
////                            return true;
////                        } else if (role.getPermissions() != null && !role.getPermissions().isEmpty()) {
////                            //否则再判断角色拥有的permission是否拥有请求资源需要的权限
////                            Iterator<Permission> iterator = role.getPermissions().iterator();
////                            //遍历拥有的全部permission
////                            while (iterator.hasNext()) {
////                                Permission permission = iterator.next();
////                                if (permission.getKeyword().equals(authority.getKeyword())) {
////                                    log.info("角色的permission权限足够，放行");
////                                    return true;
////                                }
////                            }
////                            return false;
////                        }
////                    }
////                } else {
////                    log.info("请求权限不足，不放行");
////                    //权限不足，返回405
////                    response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
////                    return false;
////                }
//                boolean pass = pass(roleSet, authority);
//                if (!pass) {
//                    response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
//                    throw new BusinessRuntimeException("用户权限不足，不能访问该资源");
//                }
//                return true;
//            } else {
//                //匹配失败，则匹配是否存在/** 标识所有请求都要认证；或者一级路径匹配成功，二级路径匹配 /* 则也匹配成功
//                String[] split = authority.getPath().split("/");
//
//                String[] target = path.split("/");
//
//                //TODO 优化为for循环遍历多级路径，而不是写死
//                //匹配到/** 判断用户是否有权限
//                if (split[1].equals("**")) {
//                    boolean pass = pass(roleSet, authority);
//                    if (!pass) {
//                        response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
//                        throw new BusinessRuntimeException("用户权限不足，不能访问该资源");
//                    }
//                    return true;
//                }
//                //匹配一级路径成功
//                if (target[1].equals(split[1])) {
//                    //判断后续等级路径
//                    if(split[2]!=null&&split[2].equals("*")||split[2].equals("**")){
//                        if (split[3]==null){
//                            boolean pass = pass(roleSet, authority);
//                            if (!pass) {
//                                response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
//                                throw new BusinessRuntimeException("用户权限不足，不能访问该资源");
//                            }
//                            return true;
//                        }else {
//                            if (split[3].equals(target[3])||split[3].equals("*")||split[3].equals("**")){
//                                boolean pass = pass(roleSet, authority);
//                                if (!pass) {
//                                    response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
//                                    throw new BusinessRuntimeException("用户权限不足，不能访问该资源");
//
//                                }
//                            }
//                        }
//                    }
//                }
//            }


            String[] authPathItem = authority.getPath().split("/");
            //遍历被权限控制的请求路径的每一层路径
            for (int i = 1; i < authPathItem.length; i++) {
                //如果请求路径为空，则没匹配上
                if (pathItem[i]==null ){
                    //没有匹配上，不需要认证权限
                    break;
                }else if (authPathItem[i].equals(pathItem[i])||authPathItem[i].equals("*")){
                    //如果当前路径等级匹配成功，则判断是否还有下一级，有的话则继续遍历，没有就说明匹配上了
                    if (i==authPathItem.length-1){
                        //如果当前路径匹配成功，则判断请求方式，
                        if (!authority.getMethod().equals(method)) continue;
                        boolean pass = pass(roleSet, authority);
                        if (!pass) {
                            response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
                            throw new BusinessRuntimeException("用户权限不足，不能访问该资源");
                        }
                        return true;
                    }else continue;
                } else if (authPathItem[i].equals("**")) {
                    //对于**的路径，则不判断请求方式，匹配所有请求方式
                    boolean pass = pass(roleSet, authority);
                    if (!pass) {
                        response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
                        throw new BusinessRuntimeException("用户权限不足，不能访问该资源");
                    }
                    return true;
                }
                break;
            }

        }

        //没有拦截，则放行
        return true;
    }


    /**
     * 判断权限是否足够
     * @param roleSet
     * @param authority
     * @return
     */
    private boolean pass(Set<Role> roleSet, AuthorityProperties.Authority authority) {
        if (roleSet != null && !roleSet.isEmpty()) {
            //遍历角色
            for (Role role : roleSet) {
                //判断当前角色自身是否包含请求资源需要的权限
                if (role.getKeyword().equals(authority.getKeyword())) {
                    log.info("角色自身请求权限足够，放行");
                    return true;
                } else if (role.getPermissions() != null && !role.getPermissions().isEmpty()) {
                    //否则再判断角色拥有的permission是否拥有请求资源需要的权限
                    Iterator<Permission> iterator = role.getPermissions().iterator();
                    //遍历拥有的全部permission
                    while (iterator.hasNext()) {
                        Permission permission = iterator.next();
                        if (permission.getKeyword().equals(authority.getKeyword())) {
                            log.info("角色的permission权限足够，放行");
                            return true;
                        }
                    }

                }
            }
            log.info("请求权限不足，不放行");
            return false;
        } else {
            log.info("请求权限不足，不放行");
            //权限不足，返回405
            return false;
        }
    }
}
